"""
限价模块
获取交易产品的最高买价和最低卖价
"""
import time
from typing import Dict, List, Optional
from datetime import datetime, timedelta
from loguru import logger

try:
    import okx.PublicData as PublicData
except ImportError:
    logger.warning("okx SDK未安装，请运行: pip install okx")
    PublicData = None


class PriceLimitManager:
    """限价管理器"""
    
    # 限速配置：20次/2s
    RATE_LIMIT_REQUESTS = 20
    RATE_LIMIT_WINDOW = 2.0  # 秒
    
    def __init__(self, sandbox: bool = True):
        """
        初始化限价管理器
        
        Args:
            sandbox: 是否使用模拟盘，True=模拟盘(1)，False=实盘(0)
        """
        if PublicData is None:
            raise ImportError("okx SDK未安装，请运行: pip install okx")
        
        self.sandbox = sandbox
        flag = "1" if sandbox else "0"
        
        # 初始化OKX公共数据API
        self.public_api = PublicData.PublicAPI(flag=flag)
        
        # 限速控制
        self.request_times: List[float] = []  # 请求时间戳列表
        
        # 数据缓存
        self.price_limit_cache: Dict[str, Dict] = {}  # inst_id -> price_limit_data
        self.cache_expire_time: Dict[str, datetime] = {}  # inst_id -> expire_time
        self.cache_duration = timedelta(minutes=1)  # 缓存1分钟
        
        logger.info(f"限价管理器已初始化 (模式: {'模拟盘' if sandbox else '实盘'})")
    
    def _check_rate_limit(self):
        """
        检查并执行限速
        限速规则：20次/2s (IP)
        """
        now = time.time()
        
        # 移除2秒前的请求记录
        self.request_times = [t for t in self.request_times 
                             if now - t < self.RATE_LIMIT_WINDOW]
        
        # 如果达到限速上限，等待
        if len(self.request_times) >= self.RATE_LIMIT_REQUESTS:
            oldest_request = self.request_times[0]
            wait_time = self.RATE_LIMIT_WINDOW - (now - oldest_request)
            
            if wait_time > 0:
                logger.debug(f"触发限速，等待 {wait_time:.2f} 秒")
                time.sleep(wait_time)
                # 重新计算
                now = time.time()
                self.request_times = [t for t in self.request_times 
                                     if now - t < self.RATE_LIMIT_WINDOW]
        
        # 记录本次请求
        self.request_times.append(now)
    
    def get_price_limit(self, inst_id: str, use_cache: bool = True) -> Dict:
        """
        获取限价（最高买价和最低卖价）
        
        Args:
            inst_id: 产品ID，如 BTC-USD-SWAP
            use_cache: 是否使用缓存
            
        Returns:
            限价信息字典，包含以下字段：
            - instType: 产品类型
            - instId: 产品ID
            - buyLmt: 最高买价
            - sellLmt: 最低卖价
            - ts: 数据返回时间（毫秒时间戳）
        """
        # 检查缓存
        if use_cache and inst_id in self.price_limit_cache:
            expire_time = self.cache_expire_time.get(inst_id)
            if expire_time and datetime.now() < expire_time:
                logger.debug(f"从缓存获取限价: {inst_id}")
                return self.price_limit_cache[inst_id]
        
        # 执行限速检查
        self._check_rate_limit()
        
        try:
            logger.info(f"获取限价: {inst_id}")
            result = self.public_api.get_price_limit(instId=inst_id)
            
            # 检查响应
            if result.get("code") != "0":
                error_msg = result.get("msg", "未知错误")
                logger.error(f"获取限价失败: {error_msg}")
                raise RuntimeError(f"API错误: {error_msg}")
            
            # 提取数据
            data_list = result.get("data", [])
            if not data_list:
                logger.warning(f"未获取到限价数据: {inst_id}")
                return {}
            
            price_limit_data = data_list[0]
            logger.info(f"获取限价成功: {inst_id}, 买价上限={price_limit_data.get('buyLmt')}, 卖价下限={price_limit_data.get('sellLmt')}")
            
            # 更新缓存
            if use_cache:
                self.price_limit_cache[inst_id] = price_limit_data
                self.cache_expire_time[inst_id] = datetime.now() + self.cache_duration
            
            return price_limit_data
            
        except Exception as e:
            logger.error(f"获取限价异常: {e}")
            raise
    
    def get_price_limit_details(self, inst_id: str) -> Dict:
        """
        获取限价详细信息（包含格式化数据）
        
        Args:
            inst_id: 产品ID
            
        Returns:
            详细信息字典：
            - inst_id: 产品ID
            - inst_type: 产品类型
            - buy_limit: 最高买价
            - sell_limit: 最低卖价
            - price_range: 价格范围（卖价-买价）
            - price_range_pct: 价格范围百分比
            - mid_price: 中间价格
            - timestamp: 数据时间（格式化）
            - timestamp_ms: 数据时间（毫秒时间戳）
        """
        price_limit_data = self.get_price_limit(inst_id)
        
        if not price_limit_data:
            raise ValueError(f"无法获取限价: {inst_id}")
        
        # 提取数据
        buy_limit = float(price_limit_data.get("buyLmt", 0))
        sell_limit = float(price_limit_data.get("sellLmt", 0))
        ts = int(price_limit_data.get("ts", 0))
        
        # 计算价格范围
        price_range = sell_limit - buy_limit
        mid_price = (buy_limit + sell_limit) / 2
        price_range_pct = (price_range / mid_price * 100) if mid_price > 0 else 0
        
        # 格式化时间
        timestamp_str = datetime.fromtimestamp(ts / 1000).strftime("%Y-%m-%d %H:%M:%S")
        
        return {
            "inst_id": inst_id,
            "inst_type": price_limit_data.get("instType"),
            "buy_limit": buy_limit,
            "sell_limit": sell_limit,
            "price_range": price_range,
            "price_range_pct": price_range_pct,
            "mid_price": mid_price,
            "timestamp": timestamp_str,
            "timestamp_ms": ts,
        }
    
    def get_multiple_price_limits(self, inst_ids: List[str]) -> Dict[str, Dict]:
        """
        批量获取多个产品的限价
        
        Args:
            inst_ids: 产品ID列表
            
        Returns:
            字典，key为产品ID，value为限价信息
        """
        results = {}
        
        for inst_id in inst_ids:
            try:
                price_limit_data = self.get_price_limit(inst_id)
                results[inst_id] = price_limit_data
            except Exception as e:
                logger.error(f"获取 {inst_id} 限价失败: {e}")
                results[inst_id] = None
        
        return results
    
    def check_price_in_limit(self, inst_id: str, price: float) -> Dict:
        """
        检查价格是否在限价范围内
        
        Args:
            inst_id: 产品ID
            price: 要检查的价格
            
        Returns:
            检查结果字典：
            - in_range: 是否在范围内
            - price: 检查的价格
            - buy_limit: 最高买价
            - sell_limit: 最低卖价
            - distance_to_buy_limit: 距离买价上限的距离
            - distance_to_sell_limit: 距离卖价下限的距离
        """
        details = self.get_price_limit_details(inst_id)
        
        buy_limit = details["buy_limit"]
        sell_limit = details["sell_limit"]
        
        in_range = buy_limit <= price <= sell_limit
        distance_to_buy = price - buy_limit
        distance_to_sell = sell_limit - price
        
        return {
            "in_range": in_range,
            "price": price,
            "buy_limit": buy_limit,
            "sell_limit": sell_limit,
            "distance_to_buy_limit": distance_to_buy,
            "distance_to_sell_limit": distance_to_sell,
            "distance_to_buy_limit_pct": (distance_to_buy / buy_limit * 100) if buy_limit > 0 else 0,
            "distance_to_sell_limit_pct": (distance_to_sell / sell_limit * 100) if sell_limit > 0 else 0,
        }
    
    def get_safe_order_price(self, inst_id: str, side: str, 
                            safety_margin_pct: float = 1.0) -> float:
        """
        获取安全的下单价格（距离限价有一定安全边距）
        
        Args:
            inst_id: 产品ID
            side: 订单方向 'buy' 或 'sell'
            safety_margin_pct: 安全边距百分比，默认1%
            
        Returns:
            安全的下单价格
        """
        details = self.get_price_limit_details(inst_id)
        
        if side.lower() == 'buy':
            # 买单：在最高买价基础上降低安全边距
            limit_price = details["buy_limit"]
            safe_price = limit_price * (1 - safety_margin_pct / 100)
        elif side.lower() == 'sell':
            # 卖单：在最低卖价基础上提高安全边距
            limit_price = details["sell_limit"]
            safe_price = limit_price * (1 + safety_margin_pct / 100)
        else:
            raise ValueError(f"无效的订单方向: {side}")
        
        logger.info(f"安全下单价格: {inst_id} {side} 限价={limit_price}, 安全价={safe_price}")
        
        return safe_price
    
    def clear_cache(self, inst_id: Optional[str] = None):
        """
        清除缓存
        
        Args:
            inst_id: 产品ID，如果为None则清除所有缓存
        """
        if inst_id:
            if inst_id in self.price_limit_cache:
                del self.price_limit_cache[inst_id]
            if inst_id in self.cache_expire_time:
                del self.cache_expire_time[inst_id]
            logger.info(f"已清除 {inst_id} 的缓存")
        else:
            self.price_limit_cache.clear()
            self.cache_expire_time.clear()
            logger.info("已清除所有限价缓存")
    
    def get_cache_stats(self) -> Dict:
        """
        获取缓存统计信息
        
        Returns:
            缓存统计字典
        """
        total_cached = len(self.price_limit_cache)
        valid_cached = sum(1 for inst_id in self.price_limit_cache.keys()
                          if inst_id in self.cache_expire_time and
                          datetime.now() < self.cache_expire_time[inst_id])
        
        return {
            "total_cached": total_cached,
            "valid_cached": valid_cached,
            "expired_cached": total_cached - valid_cached,
            "cache_duration_minutes": self.cache_duration.total_seconds() / 60,
        }


# 便捷函数
def get_price_limit(inst_id: str, sandbox: bool = True) -> Dict:
    """
    便捷函数：获取限价
    
    Args:
        inst_id: 产品ID
        sandbox: 是否使用模拟盘
        
    Returns:
        限价信息字典
    """
    manager = PriceLimitManager(sandbox=sandbox)
    return manager.get_price_limit(inst_id)


def get_price_limit_details(inst_id: str, sandbox: bool = True) -> Dict:
    """
    便捷函数：获取限价详细信息
    
    Args:
        inst_id: 产品ID
        sandbox: 是否使用模拟盘
        
    Returns:
        详细信息字典
    """
    manager = PriceLimitManager(sandbox=sandbox)
    return manager.get_price_limit_details(inst_id)


def check_price_in_limit(inst_id: str, price: float, sandbox: bool = True) -> Dict:
    """
    便捷函数：检查价格是否在限价范围内
    
    Args:
        inst_id: 产品ID
        price: 要检查的价格
        sandbox: 是否使用模拟盘
        
    Returns:
        检查结果字典
    """
    manager = PriceLimitManager(sandbox=sandbox)
    return manager.check_price_in_limit(inst_id, price)


def get_safe_order_price(inst_id: str, side: str, 
                        safety_margin_pct: float = 1.0,
                        sandbox: bool = True) -> float:
    """
    便捷函数：获取安全的下单价格
    
    Args:
        inst_id: 产品ID
        side: 订单方向 'buy' 或 'sell'
        safety_margin_pct: 安全边距百分比
        sandbox: 是否使用模拟盘
        
    Returns:
        安全的下单价格
    """
    manager = PriceLimitManager(sandbox=sandbox)
    return manager.get_safe_order_price(inst_id, side, safety_margin_pct)
